package util

func ItFilter[T any](i Iterator[T], predicate func(T) bool) Iterator[T] {
	nextOption := func() Option[T] {
		for i.HasNext() {
			cur := i.Next()
			if predicate(cur) {
				return Some(cur)
			}
		}
		return None[T]()
	}
	var peek Option[T]
	hasNext := func() bool {
		if peek == nil {
			peek = nextOption()
		}
		return !peek.IsEmpty()
	}
	next := func() T {
		if peek == nil {
			peek = nextOption()
		}
		t := peek.Get()
		peek = nil
		return t
	}
	return NewIterator(hasNext, next)
}
func ItMap[S, D any](s Iterator[S], f func(S) D) Iterator[D] {
	next := func() D {
		return f(s.Next())
	}
	return NewIterator(s.HasNext, next)
}
func ItRange(begin, end, step int) Iterator[int] {
	cur := begin
	hasNext := func() bool {
		return (cur >= begin && cur < end) || (cur > end && cur <= begin)
	}
	next := func() int {
		if hasNext() {
			c := cur
			cur = cur + step
			return c
		}
		panic("iterator without next element")
	}
	return NewIterator(hasNext, next)
}
func ItReduce[S, D any](s Iterator[S], initializer D, f func(D, S) D) D {
	r := initializer
	for s.HasNext() {
		r = f(r, s.Next())
	}
	return r
}
